/*
 * auiMenu.cpp
 *
 *  Created on: 2012-7-19
 *      Author: Yangde
 */


#include "wx/dcbuffer.h"
#include "wx/sizer.h"
#include "wx/listimpl.cpp"
#include "wx/arrimpl.cpp"


#include "auiutils.h"
#include "auimenu.h"

void auiMenuItem::SetSelect(bool select)
{
	if(select)
		item_status |= auiItemSelected;
	else
		item_status &= ~auiItemSelected;
}

bool auiMenuItem::IsSelect()
{
	return (item_status&auiItemSelected);
}

void auiMenuItem::SetSubmenuOnShow(bool show)
{

	if(show)
		item_status |= auiItemShowSubmenu;
	else
		item_status &= ~auiItemShowSubmenu;

}
bool auiMenuItem::IsSubmenuOnShow()
{
	return (item_status&auiItemShowSubmenu);
}


void auiMenuItem::SetChecked(bool check)
{
	if(check)
		item_status |= auiItemChecked;
	else
		item_status &= ~auiItemChecked;
}

bool auiMenuItem::IsChecked()
{
	return (item_status&auiItemChecked);
}

void auiMenuItem::Disable()
{
	item_status |= auiItemDisable;
}

void auiMenuItem::Enable()
{
	item_status &= ~auiItemChecked;;
}

bool auiMenuItem::IsDisable()
{
	return (item_status&auiItemChecked);
}

WX_DEFINE_OBJARRAY(auiMenuArray);
WX_DEFINE_OBJARRAY(auiMenuItemArray);

auiMenu::auiMenu()
{
	menu_bar = NULL;
	m_parent = NULL;
	m_popupMenu = NULL;
	max_group = 0;

	menu_key = 0;
	sys_char_i = -1;
}

auiMenu::~auiMenu()
{

}


auiMenuItem* auiMenu::Append(int itemid,
	                       const wxString& text,
	                       const wxBitmap &bitmap,
	                       int type)
{
	auiMenuItem* item = Append(itemid,text,type);
	item->item_bitmap =  bitmap;
	item->item_has_bitmap = true;
	return item;
}


auiMenuItem* auiMenu::Append(int itemid,
	                       const wxString& text,
	                       int type)
{
	auiMenuItem* item = new auiMenuItem(this,itemid, text, type);
	int last_pos = menu_items.GetCount();
	menu_items.Insert(item,last_pos);
	if(type==auiItemRadio)
	{
		if(last_pos>0 && menu_items.Last().item_type!=auiItemRadio)
			max_group ++;

		item->item_group = max_group;
	}
	return item;
}

auiMenuItem* auiMenu::AppendSeparator()
{
	auiMenuItem* item = new auiMenuItem(this,wxID_ANY, wxT(""), auiItemSeparator);
	int last_pos = menu_items.GetCount();
	menu_items.Insert(item,last_pos);
	return item;
}

auiMenuItem* auiMenu::AppendSubMenu(auiMenu *submenu,
	                              const wxString& text)
{
	auiMenuItem* item = new auiMenuItem(this,wxID_ANY, text, auiItemSubmenu);
	item->AttachSubMenu(submenu);

	submenu->m_parent = this;
	submenu->SetMenuType(auiMENU_SUB);
	int last_pos = menu_items.GetCount();
	menu_items.Insert(item,last_pos);
	return item;
}


void auiMenu::SetMenuBar(auiMenuBar *b)
{
	menu_bar = b;
	m_popupMenu = new auiPopupWindow(b,this);
	for(int i=0;i<menu_items.GetCount();i++)
	{
		if(menu_items[i].item_type == auiItemSubmenu)
			menu_items[i].sub_menu->SetMenuParent(b,m_popupMenu);
	}
}


void auiMenu::setTitle(const wxString &title)
{
	wxString t = title;
	FindSysKeyChar(t);
	menu_title = t;
}

int auiMenu::FindSysKeyChar(wxString &title)
{
	int index = title.Find('&');
	bool res = false;
	if(-1 != index && index<title.Length()-1)
	{
		wxUniChar key= title.GetChar(index+1);
		if(key.IsAscii())
		{

			if( (key>='0'&&key<='0')
			  ||(key>='a'&&key<='z')
			  ||(key>='A'&&key<='Z')
			  )
			{
				int keycode = key;
				if(keycode>='a'&&keycode<='z')
					keycode  = 'A'+ keycode - 'a';
				setSysKey(keycode);
				sys_char_i = index;
				res = true;
			}
		}

		title.Remove(index,1);
	}

	return res;
}

void auiMenu::SetMenuParent(auiMenuBar *b, auiPopupWindow* p)
{
	menu_bar = b;
	m_popupMenu = new auiPopupWindow(p,this);
	for(int i=0;i<menu_items.GetCount();i++)
	{
		if(menu_items[i].item_type == auiItemSubmenu)
			menu_items[i].sub_menu->SetMenuParent(b,m_popupMenu);
	}
}


void auiMenu::Popup(wxWindow *focus,bool selectFirst)
{
	int item_cnt = menu_items.GetCount();
	if(item_cnt>0){
		m_popupMenu->Popup(focus,selectFirst);
	}
}

void auiMenu::Dismiss(){

	for(int i=0;i<menu_items.GetCount();i++)
	{
		menu_items[i].SetSelect(false);
		if(GetItemType(i)==auiItemSubmenu)
		{
			if(menu_items[i].IsSubmenuOnShow())
			{
				menu_items[i].sub_menu->Dismiss();
			}
			menu_items[i].SetSubmenuOnShow(false);
		}
	}

	m_popupMenu->Dismiss();
}

void auiMenu::ResetParent()
{
	auiMenu* parent = m_parent;
	while(parent)
	{
		parent->Dismiss();
		parent = parent->m_parent;
	}

	if(menu_bar)
	{
		menu_bar->ReSet();
	}
}

bool auiMenu::MoveOnParent(wxPoint pos)
{
	auiMenu* parent = m_parent;
	while(parent)
	{
		auiPopupWindow *pWin = parent->m_popupMenu;
		wxPoint pPos = pWin->ScreenToClient(pos);
		if( pWin->HitTest(pPos) == wxHT_WINDOW_INSIDE)
		{
			pWin->ProcesMouseMove(pPos);
			return true;
		}

		parent = parent->m_parent;
	}

	wxPoint barPos = menu_bar->ScreenToClient(pos);
	if( menu_bar->HitTest(barPos) == wxHT_WINDOW_INSIDE
			  &&menu_bar->FindMenuByPosition(barPos)!=-1	)
	{
		menu_bar->ProcessMouseMove(barPos);
		return true;
	}

	return false;
}


bool auiMenu::L_ClickOnParent(wxPoint pos)
{
	auiMenu* parent = m_parent;
	while(parent)
	{
		auiPopupWindow *pWin = parent->m_popupMenu;
		wxPoint pPos = pWin->ScreenToClient(pos);
		if( pWin->HitTest(pPos) == wxHT_WINDOW_INSIDE)
		{
			pWin->ProcessLeftDown(pPos);
			return true;
		}

		parent = parent->m_parent;
	}

	wxPoint barPos = menu_bar->ScreenToClient(pos);
	if( menu_bar->HitTest(barPos) == wxHT_WINDOW_INSIDE
			  &&menu_bar->FindMenuByPosition(barPos)!=-1	)
	{
		menu_bar->ProcessLeftDown(barPos);
		return true;
	}
	return false;
}
bool auiMenu::R_ClickOnParent(wxPoint pos)
{
	auiMenu* parent = m_parent;
	while(parent)
	{
		auiPopupWindow *pWin = parent->m_popupMenu;
		wxPoint pPos = pWin->ScreenToClient(pos);
		if( pWin->HitTest(pPos) == wxHT_WINDOW_INSIDE)
		{
			return true;
		}

		parent = parent->m_parent;
	}

	wxPoint barPos = menu_bar->ScreenToClient(pos);
	if( menu_bar->HitTest(barPos) == wxHT_WINDOW_INSIDE
	&&  menu_bar->FindMenuByPosition(barPos)!=-1	)
	{
		return true;
	}
	return false;
}


bool auiMenu::ProcessKeyDown(int keycode)
{
	int select = GetSelectItem();
	if(select!=-1
			&&menu_items[select].item_type == auiItemSubmenu
			&&menu_items[select].IsSubmenuOnShow())
	{
		return menu_items[select].sub_menu->ProcessKeyDown(keycode);
	}

	bool res = false;
	int last =-1;
	switch(keycode)
	{
	case WXK_RIGHT:
		if(select!=-1
					&&menu_items[select].item_type == auiItemSubmenu
					&&!menu_items[select].IsSubmenuOnShow())
		{
			wxPoint pts = m_popupMenu->ClientToScreen(wxPoint(0,0));
			wxRect rc = m_popupMenu->GetItemRect(select);
			rc.x += (pts.x);
			rc.y += (pts.y);
			menu_items[select].sub_menu->m_popupMenu->SubMenuAdjustPosition(rc);
			menu_items[select].sub_menu->Popup(menu_bar,true);
			menu_items[select].SetSubmenuOnShow(true);
			res = true;
		}

		break;
	case WXK_LEFT:
		if(m_parent)
		{
			int old_select = m_parent->GetSelectItem();
			m_parent->DismissSubMenu();
			m_parent->SelectItem(old_select);
			res = true;
		}
		break;
	case WXK_UP:
		last = select;
		if(last!=-1)
		{
			menu_items[last].SetSelect(false);
		}
		else
		{
			last =0;
		}

		if(last==0)
			last = menu_items.GetCount();
		last--;

		if(1)
		{
			/*
			 * skip Separator item
			 */
			int z = menu_items.GetCount();//avoid endless loop
			while(menu_items[last].item_type==auiItemSeparator&&z--)
			{
				if(last==0)
					last = menu_items.GetCount();
				last--;
			}
		}
		menu_items[last].SetSelect(true);
		res = true;
		break;

	case WXK_DOWN:
		last = select;
		if(last!=-1)
		{
			menu_items[last].SetSelect(false);
		}

		if(last==menu_items.GetCount()-1)
			last = -1;
		last++;

		if(1)
		{
			/*
			 * skip Separator item
			 */
			int z = menu_items.GetCount();//avoid endless loop
			while(menu_items[last].item_type==auiItemSeparator&&z--)
			{
				if(last==menu_items.GetCount()-1)
					last = -1;
				last++;

			}
		}
		menu_items[last].SetSelect(true);
		res = true;

		break;
	case WXK_RETURN:
	case WXK_NUMPAD_ENTER:
		if(select!=-1)
		{
			bool shouh_dismiss = true;
			if(menu_items[select].item_type == auiItemSubmenu
			&&!menu_items[select].IsSubmenuOnShow())
			{
				wxPoint pts = m_popupMenu->ClientToScreen(wxPoint(0,0));
				wxRect rc = m_popupMenu->GetItemRect(select);
				rc.x += (pts.x);
				rc.y += (pts.y);
				menu_items[select].sub_menu->m_popupMenu->SubMenuAdjustPosition(rc);
				menu_items[select].sub_menu->Popup(menu_bar,true);
				menu_items[select].SetSubmenuOnShow(true);
				shouh_dismiss = false;
				res = true;
			}else if(menu_items[select].item_type == auiItemCheck)
			{
				if(menu_items[select].IsChecked())
					menu_items[select].SetChecked(false);
				else
					menu_items[select].SetChecked(true);

			}
			else if(menu_items[select].item_type == auiItemRadio)
			{
				int cur_group_id = menu_items[select].item_group;

				for(int i=0;i<GetItemCnt();i++)
				{
					if(menu_items[i].item_group==cur_group_id)
						menu_items[i].SetChecked(false);
				}
				menu_items[select].SetChecked(true);

			}

			if(shouh_dismiss)
			{
				wxNotifyEvent e(wxEVT_COMMAND_MENU_SELECTED, menu_items[select].item_id);
				m_popupMenu->GetEventHandler()->ProcessEvent(e);

				Dismiss();
				ResetParent();
			}
		}
		break;
	default:
		break;
	}

	if(res)
		m_popupMenu->Refresh(0);
	return res;

}

int auiMenu::GetSelectItem()
{
	for(int i=0;i<menu_items.GetCount();i++)
	{
		if(menu_items[i].IsSelect())
			return i;
	}
	return -1;
}

void auiMenu::UnSelectItem()
{
	for(int i=0;i<menu_items.GetCount();i++)
	{
		menu_items[i].SetSelect(false);
	}
}


void auiMenu::DismissSubMenu()
{
	for(int i=0;i<menu_items.GetCount();i++)
	{
		if(menu_items[i].IsSubmenuOnShow())
		{
			menu_items[i].sub_menu->Dismiss();
			menu_items[i].SetSubmenuOnShow(false);
		}
		menu_items[i].SetSelect(false);
	}
}


bool auiMenu::SelectItem(int index)
{
	if(index<0||index>=menu_items.GetCount())
	{
		return false;
	}

	menu_items[index].SetSelect(true);
	return true;
}


auiMenuItem* auiMenu::GetItem(int index)
{
	if(index<0||index>=menu_items.GetCount())
		return NULL;

	return &menu_items[index];
}
